package info.ericbutler.microcosm.world;

import info.ericbutler.microcosm.entities.Agent;
import info.ericbutler.microcosm.entities.UpdatingGameElement;
import info.ericbutler.microcosm.entities.ui.Harvestable;
import info.ericbutler.microcosm.entities.ui.ItemStack;
import info.ericbutler.microcosm.enums.TileType;
import info.ericbutler.microcosm.game.MicrocosmMain;
import info.ericbutler.microcosm.game.MicrocosmSettings;
import info.ericbutler.microcosm.game.SinglePlayerState;

import java.util.Random;

import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.state.StateBasedGame;

public class GameSquare implements UpdatingGameElement, Harvestable {
	public static GameSquare GRASS1, TREE1, TALL_GRASS1, TALL_TREE1, FANCY_GRASS1, WOODEN_WALL_1;
	private Animation animation;
	private int row, col, depth, width = 16, height = 16, verticalOverlap, updateInterval = 18000, timer = (int)( Math.random() * updateInterval );
	private boolean isOverlay, harvested, passable, farmable, positionAware, beenUpdated;
	private Microcosm myWorld;
	private float harvestHP;
	private ItemStack drops;
	private TileType type;

	public GameSquare() {}
	public GameSquare(int row, int col) {
		this(row, col, 0);
	}
	public GameSquare(int row, int col, int depth) {
		this.row = row;
		this.col = col;
		this.depth = depth;
	}
	
	public GameSquare(int row, int col, int depth, Microcosm world) {
		this.row = row;
		this.col = col;
		this.depth = depth;
		this.myWorld = world;
	}
	
	public GameSquare(TileType type, boolean passable, boolean farmable, boolean isOverlay, int verticalOverlap, ItemStack drops, float hhp, boolean positionAware) {
		this.type = type;
		this.passable = passable;
		this.farmable = farmable;
		this.verticalOverlap = verticalOverlap;
		this.isOverlay = isOverlay;
		this.drops = drops == null ? null : drops.clone();
		this.harvestHP = hhp;
		this.positionAware = positionAware;
	}
	@Override
	public void update(GameContainer c, StateBasedGame game, int delta) {
		if( isPositionAware() && !beenUpdated ) {
			StringBuffer tileNameSuffix = new StringBuffer();
			beenUpdated = true;
			// Check 4 neighbors, N, E, S, then W
			if( this.row > 0 && this.myWorld.getTiles()[this.row-1][this.col][this.depth].getType() == this.type ) {
				tileNameSuffix.append( "N" );
				this.myWorld.getTiles()[this.row-1][this.col][this.depth].update( c, game, delta );
			}
			if( this.col < this.myWorld.getTiles()[0].length && this.myWorld.getTiles()[this.row][this.col+1][this.depth].getType() == this.type ) {
				tileNameSuffix.append( "E" );
				this.myWorld.getTiles()[this.row][this.col+1][this.depth].update( c, game, delta );
			}
			if( this.row < this.myWorld.getTiles().length && this.myWorld.getTiles()[this.row+1][this.col][this.depth].getType() == this.type ) {
				tileNameSuffix.append( "S" );
				this.myWorld.getTiles()[this.row+1][this.col][this.depth].update( c, game, delta );
			}
			if( this.col > 0 && this.myWorld.getTiles()[this.row][this.col-1][this.depth].getType() == this.type ) {
				tileNameSuffix.append( "W" );
				this.myWorld.getTiles()[this.row][this.col-1][this.depth].update( c, game, delta );
			}
			// Apply new image
			if( tileNameSuffix.length() > 0 ) {
				if( tileNameSuffix.length() == 1 && tileNameSuffix.charAt( 0 ) == 'N' ) { tileNameSuffix.insert( 1, 'S' ); }
				if( tileNameSuffix.length() == 1 && tileNameSuffix.charAt( 0 ) == 'S' ) { tileNameSuffix.insert( 0, 'N' ); }
				if( tileNameSuffix.length() == 1 && tileNameSuffix.charAt( 0 ) == 'E' ) { tileNameSuffix.insert( 1, 'W' ); }
				if( tileNameSuffix.length() == 1 && tileNameSuffix.charAt( 0 ) == 'W' ) { tileNameSuffix.insert( 0, 'E' ); }
				this.setAnimation( MicrocosmMain.TILES.get( "WOODEN_WALL_1_"+tileNameSuffix.toString() ) );
			}
			beenUpdated = false;
		}
	}

	@Override
	public void render(GameContainer c, StateBasedGame game, Graphics g) {
		if( this.isOverlay ) {
			g.drawAnimation( MicrocosmMain.TILES.get( this.myWorld.getDefaultTileType() ), col * Microcosm.TILE_SCALE_PIXELS, row * Microcosm.TILE_SCALE_PIXELS );
		}
		g.drawAnimation( this.getAnimation(), col * Microcosm.TILE_SCALE_PIXELS, row * Microcosm.TILE_SCALE_PIXELS - (verticalOverlap * Microcosm.TILE_SCALE_PIXELS) );
	}
	
	public void updateGrow(int delta) {
		// Check every interval
		if( this.timer <= 0 ) {
			this.timer = updateInterval;
			// Grow logic
			if( !this.contains( SinglePlayerState.player.getCollisionBox() ) ) {
				switch( this.getType() ) {
					case FANCYGRASS1:
						// Run grass check
						int gNeighbors = this.myWorld.areNeighborsOf( this, TileType.FANCYGRASS1, true );
						if( new Random().nextFloat() < MicrocosmSettings.GRASS_GROW_RATES.get( gNeighbors ) ) {
							// Grow into tall grass
							this.becomeSquare( GameSquare.TALL_GRASS1.clone().setRow( row ).setCol( col ).setDepth( depth ).setMyWorld( myWorld ) );
						}
						break;
					case TALLGRASS1:
						int tgNeighbors = this.myWorld.areNeighborsOf( this, TileType.TALLGRASS1, true );
						if( new Random().nextFloat() < MicrocosmSettings.TALL_GRASS_GROW_RATES.get( tgNeighbors ) ) {
							// Grow into tall grass
							this.becomeSquare( GameSquare.TREE1.clone().setRow( row ).setCol( col ).setDepth( depth ).setMyWorld( myWorld ) );
						}
						break;
					case TREE1:
						int tNeighbors = this.myWorld.areNeighborsOf( this, TileType.TREE1, true );
						if( new Random().nextFloat() < MicrocosmSettings.TALL_GRASS_GROW_RATES.get( tNeighbors ) ) {
							// Grow into tall grass
							this.becomeSquare( GameSquare.TALL_TREE1.clone().setRow( row ).setCol( col ).setDepth( depth ).setMyWorld( myWorld ) );
						}
						break;
				}
			}
		} else {
			timer -= delta;
		}
	}
	
	@Override
	public void harvest(Agent harvester, float work) {
		if( harvested || !isFarmable() ) { return; }
		this.harvestHP -= work;
		if( !harvested && this.harvestHP <= 0 ) {
			harvester.getInventory().addItem( drops );
			harvested = true;
		}
	}
	
	public boolean isPassable() {
		return passable;
	}
	
	public boolean contains( Rectangle checkee ) {
		Rectangle myBox = new Rectangle( this.col * Microcosm.TILE_SCALE_PIXELS, this.row * Microcosm.TILE_SCALE_PIXELS, this.width, this.height );
		return myBox.intersects( checkee );
	}
	
	@Override
	public Vector2f getCenter() {
		return null;
	}
	public int getRow() {
		return row;
	}
	public GameSquare setRow(int row) {
		this.row = row;
		return this;
	}
	public int getCol() {
		return col;
	}
	public GameSquare setCol(int col) {
		this.col = col;
		return this;
	}
	public int getDepth() {
		return depth;
	}
	public GameSquare setDepth(int depth) {
		this.depth = depth;
		return this;
	}
	public Animation getAnimation() {
		return animation;
	}
	public int getWidth() {
		return width;
	}
	public GameSquare setWidth(int width) {
		this.width = width;
		return this;
	}
	public int getHeight() {
		return height;
	}
	public GameSquare setHeight(int height) {
		this.height = height;
		return this;
	}
	public boolean isOverlay() {
		return isOverlay;
	}
	public GameSquare setOverlay(boolean isOverlay) {
		this.isOverlay = isOverlay;
		return this;
	}
	public Microcosm getMyWorld() {
		return myWorld;
	}
	public GameSquare setMyWorld(Microcosm myWorld) {
		this.myWorld = myWorld;
		return this;
	}
	public float getHarvestHP() {
		return harvestHP;
	}
	public GameSquare setHarvestHP(float harvestHP) {
		this.harvestHP = harvestHP;
		return this;
	}
	
	public int getVerticalOverlap() {
		return verticalOverlap;
	}
	public GameSquare setVerticalOverlap(int verticalOverlap) {
		this.verticalOverlap = verticalOverlap;
		return this;
	}
	public boolean isHarvested() {
		return harvested;
	}
	public GameSquare setHarvested(boolean harvested) {
		this.harvested = harvested;
		return this;
	}
	public boolean isFarmable() {
		return farmable;
	}
	public GameSquare setFarmable(boolean farmable) {
		this.farmable = farmable;
		return this;
	}
	public boolean isPositionAware() {
		return positionAware;
	}
	public GameSquare setPositionAware(boolean positionAware) {
		this.positionAware = positionAware;
		return this;
	}
	public ItemStack getDrops() {
		return drops;
	}
	public GameSquare setDrops(ItemStack drops) {
		this.drops = drops == null ? null : drops.clone();
		return this;
	}
	public GameSquare setAnimation(Animation animation) {
		this.animation = animation;
		return this;
	}
	public GameSquare setPassable(boolean passable) {
		this.passable = passable;
		return this;
	}
	
	public TileType getType() {
		return type;
	}
	public void setType(TileType type) {
		this.type = type;
	}
	
	public void becomeSquare( GameSquare newSquare ) {
		this.setAnimation( newSquare.animation == null ? null : newSquare.animation.copy() );
		this.setCol( newSquare.col );
		this.setDepth( newSquare.depth );
		this.setDrops( newSquare.drops == null ? null : newSquare.drops.clone() );
		this.setFarmable( newSquare.farmable );
		this.setHarvested( newSquare.harvested );
		this.setHarvestHP( newSquare.harvestHP );
		this.setHeight( newSquare.height );
		this.setMyWorld( newSquare.myWorld );
		this.setType( newSquare.type );
		this.setOverlay( newSquare.isOverlay );
		this.setPassable( newSquare.passable );
		this.setPositionAware( newSquare.positionAware );
		this.setRow( newSquare.row );
		this.setType( newSquare.type );
		this.setVerticalOverlap( newSquare.verticalOverlap );
		this.setWidth( newSquare.width );
		this.timer = (int)( Math.random() * this.updateInterval );
	}
	
	public GameSquare clone() {
		GameSquare clone = new GameSquare();
		clone.setAnimation( this.animation == null ? null : this.animation.copy() );
		clone.setCol( this.col );
		clone.setDepth( this.depth );
		clone.setDrops( this.drops == null ? null : this.drops.clone() );
		clone.setFarmable( this.farmable );
		clone.setHarvested( this.harvested );
		clone.setHarvestHP( this.harvestHP );
		clone.setHeight( this.height );
		clone.setMyWorld( this.myWorld );
		clone.setType( this.type );
		clone.setOverlay( this.isOverlay );
		clone.setPassable( this.passable );
		clone.setPositionAware( this.positionAware );
		clone.setRow( this.row );
		clone.setType( this.type );
		clone.setVerticalOverlap( this.verticalOverlap );
		clone.setWidth( this.width );
		clone.timer = (int)( Math.random() * this.updateInterval );
		return clone;
	}
	
	public boolean equals( GameSquare compare ) {
		if( this.type == compare.getType() ) { return true; }
		return false;
	}
}
